package Day_0202.Spring;

/**
 * @author zxc
 * @date 2023/02/02 21:27
 **/
public class Spring_Circular_dependency {
    public static void main(String[] args) {
        /**
         * Spring如何解决循环依赖问题？
         * ===》
         * 1.循环依赖：
         * 即，实质上就是循环引用，也就是两个/两个以上的bean对象相互依赖对方，最终形成闭环;
         * 比如A依赖B，B依赖C，C又依赖A，形成循环依赖；
         *
         * 2.出现场景 ：
         * （1）构造器的循环依赖;
         * （2）Field属性的循环依赖;
         *
         * 3.如何进行检测
         * 即，在创建Bean的时候给Bean打标签，如果递归调用回来发现正在创建中的话，即说明发生了循环依赖;
         *
         * 4.Spring单例对象初始化步骤：
         * （1）createBeanInstance实例化 ：
         *  调用对象的构造方法实例化对象;
         * （2）populateBean属性填充：
         * 主要针对多Bean的依赖属性进行填充;
         * （3）initializeBean初始化：
         * 调用applicationContext.xml中的init初始化方法;
         *
         * ===》
         * 5.如何解决循环依赖 ：
         * （1）使用三级缓存 ：
         * a.singletonFactories : 单例对象工厂的cache缓存;
         * b.earlySingletonObjects : 提前曝光单例对象的cache缓存;
         * c.singletonObjects : 单例对象的cache缓存;
         *
         * （2）Spring中获取对象的过程 ：
         *  Spring首先从一级缓存singletonObjects中获取对象，
         *  如果获取不到对象并且对象正在创建中，就再从二级缓存earlySingletonObjects中获取;
         *  如果还是获取不到且允许singletonFactories通过getObject方法获取;
         *  就从三级缓存singletonFactories中获取，如果获取到了，就从singletonFactories三级缓存中进行移除，
         *  并放入earlySingletonObjects中，其实质上就是从三级缓存中移动到二级缓存中;
         *
         * ===》
         * 整个流程大致如下：
         * 1. 首先 A 完成初始化第一步并将自己提前曝光出来（通过 ObjectFactory 将自己提前曝光），
         * 在初始化的时候，发现自己依赖对象 B，此时就会去尝试 get(B)，这个时候发现 B 还没有被创建出来；
         *
         * 2. 然后 B 就走创建流程，在 B 初始化的时候，同样发现自己依赖 C，C 也没有被创建出来；
         *
         * 3. 这个时候 C 又开始初始化进程，但是在初始化的过程中发现自己依赖 A，于是尝试 get(A)。
         * 这个时候由于 A 已经添加至缓存中（一般都是添加至三级缓存 singletonFactories），通过ObjectFactory 提前曝光，
         * 所以可以通过 ObjectFactory.getObject() 方法来拿到 A 对象。
         * C 拿到 A 对象后顺利完成初始化，然后将自己添加到一级缓存中；
         *
         * 4. 回到 B，B 也可以拿到 C 对象，完成初始化，A 可以顺利拿到 B 完成初始化。到这里整个链路就已经完成了初始化过程了。
         *
         * ===》
         * 总结 ：
         * （1）初始化某个Bean（A）时，若是其依赖于另外bean（B），则会将该Bean（A）存储在三级缓存singletonFactories中;
         * （2）某个Bean（C），其所依赖的Bean（A）存储在三级缓存singletonFactoreis中，说明其Bean（A）正在进行初始化;
         * （3）将Bean(A)提前曝光，移入到二级缓存earlySingletonObjects中，使得Bean（C）完成初始化;
         * ===》实质上，依靠 1.三级缓存 && 2.提前曝光;
         */
    }

}
